package org.jfk.core.interceptor;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.jfk.core.model.HttpRequestBlackList;
import org.jfk.core.model.HttpRequestLog;
import org.jfk.core.utils.AntiPourUtil;
import org.jfk.core.utils.JsonUtil;
import org.jfk.sys.user.User;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;

/**
 * 记录http访问日志
 * 
 * @author Administrator jiangxf
 * 
 */
public class HttpRequestLogInterceptor implements Interceptor {

	private static Map<String, Long> reqtime = new HashMap<String, Long>();
	private static Map<String, Long> reqbusy = new HashMap<String, Long>();

	@Override
	public void intercept(Invocation inv) {
		String errMsg = null;
		try {
			String actionKey = inv.getActionKey();
			Object[] args = inv.getArgs();
			Controller ctl = inv.getController();
			HttpServletRequest req = ctl.getRequest();
			HttpSession session = req.getSession();
			User user = (User) session.getAttribute("currUser");
			Object userId = null;
			if (user != null) {
				userId = user.get("ID");
			}
			String contextPath = req.getContextPath();
			String queryString = req.getQueryString();
			// String remoteAddr = req.getRemoteAddr();
			String remoteAddr = req.getHeader("X-Real-IP");
			if (StrKit.isBlank(remoteAddr)) {
				remoteAddr = req.getRemoteAddr();
			}

			String localAddr = req.getLocalAddr();
			int port = req.getLocalPort();
			localAddr = localAddr + ":" + port;

			Map paraMap = req.getParameterMap();
			String paras = JsonUtil.map2jsonStr(paraMap);


			String ctlKey = inv.getControllerKey();
			String methodName = inv.getMethodName();
			Method mth = inv.getMethod();
			Object returnValue = inv.getReturnValue();
			Object target = inv.getTarget();
			String target1 = target.getClass().getName();
			String viewPath = inv.getViewPath();

			Enumeration headerNames = req.getHeaderNames();
			String header = null;
			Map headerMap = new HashMap();
			String referer = null;
			String userAgent = null;
			while (headerNames.hasMoreElements()) {
				Object key = headerNames.nextElement();
				Object value = req.getHeader(key.toString());
				headerMap.put(key, value);
				if ("user-agent".equals(key)) {
					userAgent = value.toString();
				}
				if ("referer".equals(key)) {
					referer = value.toString();
				}
			}
			header = JsonUtil.map2jsonStr(headerMap);

			Enumeration attributeNames = req.getAttributeNames();
			String attr = null;
			Map attrMap = new HashMap();
			while (attributeNames.hasMoreElements()) {
				Object key = attributeNames.nextElement();
				Object value = req.getAttribute(key.toString());
				attrMap.put(key, value);
			}
			attr = JsonUtil.map2jsonStr(attrMap);

			Cookie[] cookies = req.getCookies();
			String cookieStr = null;
			Map cookieMap = new HashMap();
			if (cookies != null && cookies.length > 0) {
				for (Cookie cookie : cookies) {
					Object key = cookie.getName();
					Object value = cookie.getValue();
					cookieMap.put(key, value);
				}
			}
			cookieStr = JsonUtil.map2jsonStr(cookieMap);
			


			HttpRequestLog log = new HttpRequestLog();
			log.set("remote_ip", remoteAddr);
			log.set("local_ip", localAddr);
			log.set("context_path", contextPath);
			log.set("req_url", actionKey);
			log.set("req_querystr", queryString);
			log.set("param", paras);
			log.set("header", header);
			log.set("user_agent", userAgent);
			log.set("referer", referer);
			log.set("cookies", cookieStr);
			log.set("session_user", userId);
			log.set("jfinal_method", methodName);
			log.set("jfinal_controller", target.getClass().getName());
			log.set("create_time", new Timestamp(System.currentTimeMillis()));
			log.save();
			req.setAttribute("requestId", log.get("ID"));
			
			// 黑名单拦截
			if (!HttpRequestBlackList.dao.isAllow(remoteAddr, actionKey)) {
				Map<String, Object> obj = new HashMap<String, Object>();
				obj.put("suc", "n");
				obj.put("err", "请求被禁止");
				inv.getController().renderJson(obj);
				return;
			}

			// 脚本注入拦截
			if (!AntiPourUtil.checkJSPour(queryString)
					|| !AntiPourUtil.checkJSPour(paras)) {
				
				errMsg = "禁止脚本注入";

			}			

			//跨域拦截
//			if (userAgent.contains("android") || userAgent.contains("iphone") || methodName.equals("index")) {
//				// 手机不查跨域、首页不检查跨域
//			} else {
//				// 非手机检查跨域
//				if (referer == null || !referer.contains(req.getServerName())) {
//					errMsg = "禁止跨域请求";
//				}
//			}


			// 频繁调用拦截
			String key = remoteAddr + "-" + actionKey;
			Long time = reqtime.get(key);
			if (time == null) {
				time = new Long(System.currentTimeMillis());
				reqtime.put(key, time);
			} else {

				long t1 = time.longValue();
				long t2 = System.currentTimeMillis();
				time = new Long(t2);
				reqtime.put(key, time);
				if (t2 - t1 < 300) {
					System.out.println(key + " 频繁调用");
					Long busy = reqbusy.get(key);
					if (busy == null) {
						busy = new Long(1);
						reqbusy.put(key, busy);
					} else {
						int b = busy.intValue();
						reqbusy.put(key, new Long(b + 1));
						if (b > 5) {
							long currTime = System.currentTimeMillis();
							Timestamp ts = new Timestamp(currTime);
							System.out.println(key + " - " + ts + " 次数过多 " + b);
							errMsg = "禁止连续高频请求";
						}
					}
				} else {
					reqbusy.put(key, new Long(0));
				}
			}
			
			if (errMsg != null){
				HttpRequestBlackList backList = new HttpRequestBlackList();
				backList.set("remote_ip", remoteAddr);
				backList.set("req_url", actionKey);
				backList.set("create_time",
						new Timestamp(System.currentTimeMillis()));
				backList.set("remark", errMsg);
				backList.save();

				Map<String, Object> obj = new HashMap<String, Object>();
				obj.put("suc", "n");
				obj.put("err", errMsg);
				inv.getController().renderJson(obj);
				return;
				
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		inv.invoke();
		
		//修复X-Frame-Options未配置，frame页面的地址只能为同源域名下的页面
		HttpServletResponse resp = inv.getController().getResponse();
		resp.addHeader("x-frame-options","SAMEORIGIN");
	}

}
